Skip to content

feat(policy): Enforce org-required local model downloads - #1836

Merged
Chadpiha merged 3 commits into
mainfrom
feat/required-local-models
Aug 25, 2026
Merged

feat(policy): Enforce org-required local model downloads#1836
Chadpiha merged 3 commits into
mainfrom
feat/required-local-models

Conversation

@Chadpiha

Copy link
Copy Markdown
Collaborator

Summary

Desktop half of enterprise-enforced model downloads (requiredLocalModels):

Onboarding gate — managed users with required models missing on disk hit a blocking required-models step right after sign-in: sequential auto-started downloads with per-row progress and retry, a dead-end alert card for repeated failures, Back/Skip suppressed, Continue gated on disk truth. The step is latched into the session (survives relaunch mid-download), and a capture effect pulls a just-signed-in session back from permissions once the policy and disk checks settle. Guest path untouched.

Fleet gate — already-onboarded managed users get a non-dismissable amber ControlPanel banner (mirrors the update-required banner) with an inline download action; it reappears if a required model is deleted later. Nag surface, not a hard block.

Plumbing — shape-only validation (policyValidation.js) so future server-side ids can't invalidate the whole managed policy; requiredLocalModelIds filters to registry-known ids with a warning; shared useRequiredLocalModels hook joins policy with disk truth; new openwhispr-local-models-changed event re-checks after downloads/deletions anywhere in the window. i18n keys in all 10 locales.

Deploy order

Ships last: API → console → desktop release. Admins should then set Minimum app version ≥ this release.

Testing

  • npm test: 2812 pass, 0 fail (10 new: route insertion/ordering/clamping/progress, validator shape cases, selector filtering/set-difference)
  • npm run typecheck, npm run lint, npm run format:check, npm run i18n:check all clean
  • Manual staging E2E (SSO flow, network-kill mid-download, quit/resume, guest path, multi-workspace union, Windows) still pending

Managed users whose org requires local models (requiredLocalModels)
now hit a blocking onboarding step right after sign-in: required
whisper/parakeet models download sequentially with per-row progress
and retry, Back/Skip are suppressed, and Continue is gated on disk
truth. The step is latched into the session so a mid-download policy
refresh cannot rebuild the route under the user, and a capture effect
pulls a just-signed-in session back from the permissions step once the
policy and disk checks settle.

Already-onboarded users get a non-dismissable ControlPanel banner with
an inline download action instead of a hard block. Disk truth drives
both surfaces via useRequiredLocalModels; a new
openwhispr-local-models-changed event re-checks after downloads and
deletions anywhere in the window. Policy validation stays shape-only
so future server-side model ids cannot invalidate the managed policy —
unknown ids are filtered at enforcement time, with minAppVersion as
the backstop.
The background download tray subscribes to all model download progress
events, so it duplicated the required-models step's own progress pill
and offered a cancel that cannot stick — the step auto-restarts
org-mandated downloads, making the cancel silently ineffective.

Drop row-creating events while the persisted onboarding session sits on
the required-models step. Completions still pass so a pre-existing row
from a resumed local-setup download can clear and activate normally.
policyRules is imported by SyncService, whose node-run tests stub a
partial window. Importing ModelRegistry pulled in the settings and
enterprise-identity stores, whose module scope calls window.setInterval
when any window exists — crashing all 11 syncServiceFolders tests in CI
at load time (they skip locally on the DB-binding ABI, which is why the
local run stayed green).

requiredLocalModelIds only needs the registry's model ids, so read
modelRegistryData.json directly, the same pattern policyValidation.js
already uses. This restores the lean module graph policyRules had
before the requiredLocalModels feature.
@Chadpiha
Chadpiha merged commit 409bc28 into main Aug 25, 2026
9 checks passed
github-actions Bot pushed a commit to PlaybookMediaLLC/openwhispr that referenced this pull request Aug 26, 2026
# [1.11.0](v1.10.0...v1.11.0) (2026-08-26)

### Bug Fixes

* **ai:** retry HTTP 408 request timeouts in the API retry strategy ([OpenWhispr#1734](https://github.com/PlaybookMediaLLC/openwhispr/issues/1734)) ([d3661cb](d3661cb))
* **auth:** Unify onboarding and reauthentication display ([OpenWhispr#1763](https://github.com/PlaybookMediaLLC/openwhispr/issues/1763)) ([3cc197f](3cc197f))
* **calendar:** fail OAuth loopback immediately on state mismatch ([OpenWhispr#1753](https://github.com/PlaybookMediaLLC/openwhispr/issues/1753)) ([8b77a59](8b77a59))
* **calendar:** group date-only upcoming events on the local calendar day ([2ef397b](2ef397b))
* **calendar:** resolve Microsoft series masters through their calendar ([OpenWhispr#1835](https://github.com/PlaybookMediaLLC/openwhispr/issues/1835)) ([a0bbf4f](a0bbf4f))
* **chat:** persist conversation migration links ([OpenWhispr#1772](https://github.com/PlaybookMediaLLC/openwhispr/issues/1772)) ([15b5b3f](15b5b3f))
* click should be the delibrate action to select model for STT models ([90cfe03](90cfe03))
* **cli:** enforce request body byte limit ([OpenWhispr#1777](https://github.com/PlaybookMediaLLC/openwhispr/issues/1777)) ([996fe79](996fe79))
* **cli:** preserve UTF-8 request bodies ([OpenWhispr#1386](https://github.com/PlaybookMediaLLC/openwhispr/issues/1386)) ([ef627c9](ef627c9))
* **diarization:** diarize the mic track for in-person meetings — fixes [OpenWhispr#1627](https://github.com/PlaybookMediaLLC/openwhispr/issues/1627) ([0a10184](0a10184))
* **diarization:** skip orphan speaker embeddings in softened mic mode ([2ffbe35](2ffbe35))
* **dictation:** initialize onboarding event ref safely ([OpenWhispr#1756](https://github.com/PlaybookMediaLLC/openwhispr/issues/1756)) ([c5d515b](c5d515b))
* dismiss dictation preview when no audio detected ([OpenWhispr#1667](https://github.com/PlaybookMediaLLC/openwhispr/issues/1667)) ([7208bdf](7208bdf))
* **history:** keep the wide two-column layout regardless of calendar connection ([d45d1d2](d45d1d2))
* **i18n:** guard localStorage deref against partial window stubs ([OpenWhispr#1842](https://github.com/PlaybookMediaLLC/openwhispr/issues/1842)) ([0686a26](0686a26))
* **linux:** map KDE punctuation hotkeys to Qt key codes ([OpenWhispr#1752](https://github.com/PlaybookMediaLLC/openwhispr/issues/1752)) ([523acab](523acab))
* **linux:** Preserve focus for Sway overlays ([OpenWhispr#1718](https://github.com/PlaybookMediaLLC/openwhispr/issues/1718)) ([063b5b6](063b5b6))
* **linux:** push-to-talk on Wayland (Hyprland, KDE, GNOME 48+) for dictation hotkey ([OpenWhispr#1738](https://github.com/PlaybookMediaLLC/openwhispr/issues/1738)) ([b5c5fb4](b5c5fb4))
* **local-llm:** Phase 0 correctness + hygiene fixes for local model params and canaries ([OpenWhispr#1714](https://github.com/PlaybookMediaLLC/openwhispr/issues/1714)) ([41cf1d4](41cf1d4)), closes [OpenWhispr#1176](https://github.com/PlaybookMediaLLC/openwhispr/issues/1176) [OpenWhispr#1021](https://github.com/PlaybookMediaLLC/openwhispr/issues/1021) [OpenWhispr#1611](https://github.com/PlaybookMediaLLC/openwhispr/issues/1611)
* **logging:** Suppress packaged Windows console output ([OpenWhispr#1719](https://github.com/PlaybookMediaLLC/openwhispr/issues/1719)) ([30dedcf](30dedcf))
* make model selection an explicit click and only bootstrap if no model is selected/downloaed ([b9b5335](b9b5335))
* **meeting:** handle nullish segments and non-object patches in speakerAssignmentPolicy ([OpenWhispr#1798](https://github.com/PlaybookMediaLLC/openwhispr/issues/1798)) ([c519e1f](c519e1f)), closes [OpenWhispr#1797](https://github.com/PlaybookMediaLLC/openwhispr/issues/1797)
* Mode-switch validity guard ([58d9af0](58d9af0))
* **models:** Honor redirected cache roots ([OpenWhispr#1721](https://github.com/PlaybookMediaLLC/openwhispr/issues/1721)) ([da39195](da39195)), closes [OpenWhispr#1279](https://github.com/PlaybookMediaLLC/openwhispr/issues/1279)
* **network:** treat the full IPv6 link-local range as private HTTP ([OpenWhispr#1733](https://github.com/PlaybookMediaLLC/openwhispr/issues/1733)) ([1fe91f2](1fe91f2))
* **notes:** abort local transcription and diarization when an upload is cancelled — fixes [OpenWhispr#1401](https://github.com/PlaybookMediaLLC/openwhispr/issues/1401) ([7bbc04c](7bbc04c))
* **notes:** format future timestamps as dates ([OpenWhispr#1768](https://github.com/PlaybookMediaLLC/openwhispr/issues/1768)) ([5d5f08c](5d5f08c))
* **notes:** keep markdown mirror paths inside base ([OpenWhispr#1773](https://github.com/PlaybookMediaLLC/openwhispr/issues/1773)) ([2893be4](2893be4))
* **notes:** keep note content visible above the floating chat panel ([OpenWhispr#1769](https://github.com/PlaybookMediaLLC/openwhispr/issues/1769)) ([fa11ddc](fa11ddc))
* **notes:** reject cancelled uploads before ffmpeg conversion and server boot ([53ec075](53ec075))
* **parakeet:** Clarify unsupported-macOS guidance and dedupe version compare ([cd4dedc](cd4dedc)), closes [OpenWhispr#862](https://github.com/PlaybookMediaLLC/openwhispr/issues/862) [OpenWhispr#764](https://github.com/PlaybookMediaLLC/openwhispr/issues/764) [OpenWhispr#862](https://github.com/PlaybookMediaLLC/openwhispr/issues/862)
* **parakeet:** Gate incompatible macOS runtime ([0c271fe](0c271fe)), closes [OpenWhispr#862](https://github.com/PlaybookMediaLLC/openwhispr/issues/862)
* **parakeet:** Localize disabled provider tab labels ([514866c](514866c)), closes [OpenWhispr#862](https://github.com/PlaybookMediaLLC/openwhispr/issues/862)
* **paste:** skip trailing space after CJK text in append smart spacing ([OpenWhispr#1823](https://github.com/PlaybookMediaLLC/openwhispr/issues/1823)) ([f26b059](f26b059))
* retire dead cloud models and make the canary suites trustworthy ([OpenWhispr#1722](https://github.com/PlaybookMediaLLC/openwhispr/issues/1722)) ([9b3f57a](9b3f57a))
* **settings:** Clamp the LLM request timeout input on blur ([7032088](7032088))
* **settings:** close stale-state gaps in explicit model selection ([82fd37a](82fd37a))
* **settings:** enforce auto-end and request timeout defaults ([OpenWhispr#1755](https://github.com/PlaybookMediaLLC/openwhispr/issues/1755)) ([77c6661](77c6661))
* **settings:** harden browse-only provider tabs and drop dead code ([983bf58](983bf58))
* **settings:** keep the browsed whisper-list validation off foreign local models ([204e83b](204e83b))
* **snippets:** do not crash snippet expansion when the list is nullish ([773fed0](773fed0))
* **stores:** Survive imports under partial browser window stubs ([OpenWhispr#1841](https://github.com/PlaybookMediaLLC/openwhispr/issues/1841)) ([b934b88](b934b88))
* **uploads:** anchor upload transcript timestamps to the meeting path's epoch-ms base ([df826f0](df826f0))
* **uploads:** normalize provider names and clamp verbose segment timestamps ([OpenWhispr#1800](https://github.com/PlaybookMediaLLC/openwhispr/issues/1800)) ([d9499f5](d9499f5)), closes [OpenWhispr#1799](https://github.com/PlaybookMediaLLC/openwhispr/issues/1799)
* **utils:** handle nullish and invalid inputs safely in date formatting ([OpenWhispr#1783](https://github.com/PlaybookMediaLLC/openwhispr/issues/1783)) ([OpenWhispr#1784](https://github.com/PlaybookMediaLLC/openwhispr/issues/1784)) ([858e824](858e824))
* validate transcription hosts exactly ([8aced79](8aced79))
* **whisper:** accept any casing for the GPU opt-out flag ([28bf6f4](28bf6f4))
* **whisper:** engage downloaded GPU packs without the env flag ([d4c207a](d4c207a)), closes [OpenWhispr#1340](https://github.com/PlaybookMediaLLC/openwhispr/issues/1340)
* **whisper:** raise decoder anti-hallucination thresholds on local transcription — fixes [OpenWhispr#1458](https://github.com/PlaybookMediaLLC/openwhispr/issues/1458) ([b7fdf80](b7fdf80))
* **windows:** block untrusted file navigation ([OpenWhispr#1776](https://github.com/PlaybookMediaLLC/openwhispr/issues/1776)) ([45c20b8](45c20b8))
* **windows:** restore the captured target window before pasting — fixes [OpenWhispr#859](https://github.com/PlaybookMediaLLC/openwhispr/issues/859) ([de9e335](de9e335)), closes [OpenWhispr#668](https://github.com/PlaybookMediaLLC/openwhispr/issues/668)

### Features

* **billing:** self-serve Enterprise upgrade + admin console entry ([OpenWhispr#1623](https://github.com/PlaybookMediaLLC/openwhispr/issues/1623)) ([e039861](e039861))
* **calendar:** add provider-neutral availability tool ([OpenWhispr#1821](https://github.com/PlaybookMediaLLC/openwhispr/issues/1821)) ([b96f4a2](b96f4a2))
* **calendar:** redesign Coming up sidebar with join-and-take-notes and empty states ([a5e59ee](a5e59ee))
* complete Oppulence Voice cloud integration ([fed389c](fed389c))
* **hyprland:** support both Lua and legacy configs ([OpenWhispr#1664](https://github.com/PlaybookMediaLLC/openwhispr/issues/1664)) ([47da21d](47da21d))
* **llm:** Apply the configurable request timeout to the Tinfoil provider ([f240775](f240775)), closes [OpenWhispr#1479](https://github.com/PlaybookMediaLLC/openwhispr/issues/1479)
* **meetings:** Auto-end forgotten meeting recordings ([OpenWhispr#1494](https://github.com/PlaybookMediaLLC/openwhispr/issues/1494)) ([bc306d2](bc306d2))
* **models:** add Gemini 3.5 and 3.1 Flash Lite models ([OpenWhispr#1702](https://github.com/PlaybookMediaLLC/openwhispr/issues/1702)) ([90f79b6](90f79b6))
* **notes:** real speaker identity in note generation and [@mention](https://github.com/mention) owner tagging ([672cc90](672cc90))
* **onboarding:** rebuild guided setup experience ([OpenWhispr#1670](https://github.com/PlaybookMediaLLC/openwhispr/issues/1670)) ([9382171](9382171)), closes [#141414](https://github.com/PlaybookMediaLLC/openwhispr/issues/141414)
* **policy:** Enforce org-required local model downloads ([OpenWhispr#1836](https://github.com/PlaybookMediaLLC/openwhispr/issues/1836)) ([409bc28](409bc28))
* **policy:** Mirror the server-only memoryEnabled org-policy field ([OpenWhispr#1717](https://github.com/PlaybookMediaLLC/openwhispr/issues/1717)) ([91c1195](91c1195))
* **sidebar:** redesign Upgrade to Pro banner to new card style ([973cbf5](973cbf5))
* **uploads:** persist segment timestamps from BYOK cloud transcriptions for SRT export — fixes [OpenWhispr#1095](https://github.com/PlaybookMediaLLC/openwhispr/issues/1095) ([aada021](aada021))

### Performance Improvements

* **windows:** skip the paste settle when the target is already foreground ([0266639](0266639))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant